package main

import (
	//"errors"
	"flag"
	"fmt"
	//"io"
	"log"
	"net"
	"os"
	"strconv"
	p2p "p2p-go/p2plib"
)

var debug p2p.DebugLog

func printVersion() {
	const version = "0.0.1"
	fmt.Println("ss p2p go version", version)
}


func handleConnection(conn net.Conn) {
	debug.Printf("open connection from client: %s\n", conn.RemoteAddr().String())

	closed := false
	defer func() {
		if !closed {
			conn.Close()
		}
	}()

	var err error = nil

	remote, err := net.Dial("tcp", p2p.RemoteServer + ":" + strconv.Itoa(p2p.RemotePort))
	if err != nil {
		log.Println("Failed connect to remote shadowsocks server")
		return
	}
	defer func() {
		if !closed {
			remote.Close()
		}
	}()

	go p2p.PipeThenClose(conn, remote)
	p2p.PipeThenClose(remote, conn)

	closed = true
	debug.Println("closed connection to", conn.RemoteAddr().String())
}

func run(listenAddr string) {
	ln, err := net.Listen("tcp", listenAddr)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("starting p2p server at %v ...\n", listenAddr)
	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Println("accept:", err)
			continue
		}
		go handleConnection(conn)
	}
}

func main() {
	log.SetOutput(os.Stdout)

	var remoteServer string
	var remotePort int
	var localAdd string
	var localPort int
	var timeout int
	var printVer bool

	flag.BoolVar(&printVer, "version", false, "print version")
	flag.StringVar(&remoteServer, "s", "", "remote server address")
	flag.IntVar(&remotePort, "p", 8388, "remote server port")
	flag.StringVar(&localAdd, "b", "", "local address")
	flag.IntVar(&localPort, "l", 8388, "local port")
	flag.IntVar(&timeout, "t", 300, "timeout in seconds")
	flag.BoolVar((*bool)(&debug), "d", false, "print debug message")

	flag.Parse()

	if printVer {
		printVersion()
		os.Exit(0)
	}

	if remoteServer == "" {
		fmt.Println("remote server address is required, use -s to specify. ")
		os.Exit(0)
	}

	p2p.RemoteServer = remoteServer
	p2p.RemotePort = remotePort
	p2p.LocalAdd = localAdd
	p2p.LocalPort = localPort
	p2p.SetTimeout(timeout)

	run(localAdd + ":" + strconv.Itoa(localPort))
}
